﻿using SoundEngine3.DspPlugins.Meta;
using SoundEngine3.SequenceContent;
using SteganoMidi;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ZquenceStudio3.Core.Formats;
using ZquenceStudio3.Core.Album;

namespace MidiFormats
{
    public class MidiExporterImporterFormat : BaseImportFormat
    {
        public override string[] AlbumFilenameType
        {
            get
            {
                return new string[] { };
            }
        }
    
        public override string AlbumFormatName
        {
            get
            {
                return string.Empty;
            }
        }
    
    
        public override string[] SongFilenameType
        {
            get
            {
                return new string[] { ".mid" };
            }
        }
    
        public override string SongFormatName
        {
            get
            {
                return "MIDI";
            }
        }
        public override Version FormatVersion
        {
            get
            {
                return new Version(1, 0, 0, 0);
            }
        }

        public override bool FileSupported(Stream stream)
        {
            return true;
        }
    
        public override void OpenAlbum(string path, AlbumSolutionFile root, FormatProgress progress)
        {
            throw new NotImplementedException();
        }
    
        public override void OpenSong(Song song, FormatProgress progress)
        {
            string filePath = song.FilePath;
    
            int maxProgress = 0;
            //m_loadingProgress = 0;
    
            MidiFileReader m_midiFileReader = new MidiFileReader();
    
            string report = null;
            int countProgramChange = 0;
            long fileSize = 0;
    
            // Read midi file.
            HumanReadableMidi midi = new HumanReadableMidi();
    
            using (var stream = SharpDepend.Manager.FileManager.OpenFile(filePath))
            {
                m_midiFileReader.ReadFile(stream, out report, out countProgramChange, out fileSize, midi);
            }
    
            // Max progress value.
            maxProgress = 1 + midi.Tracks.Count;
    
            List<Sequence> currentSequences = new List<Sequence>();
            List<Reference> currentReferences = new List<Reference>();
            List<Pattern> currentPattern = new List<Pattern>();
    
            // Recalculate the devision.
            double rescaleDevision = Context.SoundEngine.Sequencer.Time.PpqResolution / midi.Division;
    
            // Set tempo.
            Context.SoundEngine.Sequencer.Time.Tempo = midi.Tempo;
    
            // Loop every pattern data.
            short trackPosition = -1;
            foreach (var patternData in midi.Tracks)
            {
                // Calculate loading progress.
                //CalcProgress(++m_loadingProgress, maxProgress);
    
                if (patternData.Notes.Count == 0)
                {
                    continue;
                }
    
                // Add a default track.
                Track track = Context.SoundEngine.Sequencer.CreateTrack(patternData.Name);
                track.DspSynthesizer = Context.SoundEngine.DspPluginManager.CreateDspInstance(Context.SoundEngine.DspPluginManager.AvailableDspSynthesizers[0]);
                track.DspSynthesizer.MixerChannel = Context.SoundEngine.Mixerboard.MasterMixerChannel;
    
                // Add a pattern.
                Pattern pattern = Context.SoundEngine.Sequencer.CreatePattern(patternData.Name);
                currentPattern.Add(pattern);
    
                // Add a sequence.
                Sequence sequence = Context.SoundEngine.Sequencer.CreateSequence(track, pattern);
    
                // Create a new reference and insert in in TrackRoom.
                Reference newReference = Context.SoundEngine.Sequencer.CreateReference(pattern);
                Context.SoundEngine.Sequencer.AddReference(pattern, newReference);
                newReference.Start = 0;
                newReference.TrackStationIndex = ++trackPosition;
                currentReferences.Add(newReference);
                currentSequences.Add(sequence);
    
                // Loop every note data.
                foreach (var noteData in patternData.Notes)
                {
                    Note note = Context.SoundEngine.Sequencer.CreateNote();
                    note.Start = noteData.Start * rescaleDevision;
                    note.Length = noteData.Length * rescaleDevision;
                    note.NoteKey = noteData.NoteKey;
                    note.Velocity = noteData.Velocity;
                    sequence.AddNote(note);
    
                    // It's not allowed to have length at 0.
                    if (note.Length == 0)
                    {
                        note.Length = 1;
                    }
                }
            }
    
            // Sort notes. Problebly not nessesary, notes are already sorted i think.
            foreach (var sequence in currentSequences)
            {
                sequence.SortNotes();
            }
    
            // Auto justify the length of all references now when all notes is in them.
            foreach (var reference in currentReferences)
            {
                reference.AutoJustifyLength = true;
            }
        }
    }
}
